package etes;

import java.util.TreeMap;

import com.csvreader.CsvReader;

public class Application {

	
	public static void main (String[] args){
		if (args.length != 1)
			System.exit(0);
		else
			System.out.println(args[0]);
	
		try
		{
			CsvReader orderFile = new CsvReader(args[0]);
			
			/* if file opened successfully, create a map of instruments to their respective orderbooks */
			TreeMap<String, OrderBook> instrumentBook = new TreeMap<String, OrderBook>();
			loadOrders(orderFile, instrumentBook);	
			/* if file opened successfully, create an orderbook and set priority values */
			for (OrderBook OB : instrumentBook.values())		
			{
				//OB.printBids();
				//OB.printAsks();
				
				OB.out();
				
			}
			
			System.out.println("All records posted");
		}
		catch (Exception e)
		{
			System.out.println(e.getMessage());
		}

	}
	
	/* this function loads all the orders in the csv file */
	private static void loadOrders(CsvReader orderFile, TreeMap<String, OrderBook> instrumentBook) {
		try
		{
			/* read headers in so we can load values directly */
			orderFile.readHeaders();
			/* loop through each order in the CSV, create an etes.Order, 
			 * populate fields and add it to the correct orderbook */
			while (orderFile.readRecord())
			{
				Order newOrder = new Order();
				String instrument = orderFile.get("Instrument");
				newOrder.setInstrument(instrument);
				newOrder.setRecordType(orderFile.get("Record Type"));
				newOrder.setPrice(makeDoubleFromCSV(orderFile.get("Price")));
				newOrder.setVolume(makeIntFromCSV(orderFile.get("Volume")));
				newOrder.setUndisclosedVolume(makeIntFromCSV(orderFile.get("Undisclosed Volume")));
				newOrder.setValue(makeDoubleFromCSV(orderFile.get("Value")));
				newOrder.setQualifiers(orderFile.get("Qualifiers"));
				newOrder.setTransID(makeIntFromCSV(orderFile.get("Trans ID")));
				newOrder.setBidID(orderFile.get("Bid ID"));
				newOrder.setAskID(orderFile.get("Ask ID"));
				newOrder.setBidAsk(orderFile.get("Bid/Ask"));
				newOrder.setEntryTime(orderFile.get("Entry Time"));
				newOrder.setOldPrice(makeDoubleFromCSV(orderFile.get("Old Price")));
				newOrder.setOldVolume(makeIntFromCSV(orderFile.get("Old Volume")));
				newOrder.setBuyerBrokerID(makeIntFromCSV(orderFile.get("Buyer Broker ID")));
				newOrder.setSellerBrokerID(makeIntFromCSV(orderFile.get("Seller Broker ID")));
				newOrder.setOrderDate(orderFile.get("Date"));
				newOrder.setOrderTime(orderFile.get("Time"));
				
				if (!instrumentBook.containsKey(instrument)) {
					instrumentBook.put(instrument, new OrderBook());
					instrumentBook.get(instrument).setInstrumentName(instrument);
				}
					
				
				/* update bid/order priorities then add it to the correct side of the orderbook */
				if (newOrder.getRecordType().equals("ENTER") && newOrder.getBidAsk().equals("B"))
					postBid(instrumentBook.get(instrument), newOrder);
				else if (newOrder.getRecordType().equals("ENTER") && newOrder.getBidAsk().equals("A"))
					postAsk(instrumentBook.get(instrument), newOrder);
				else if (newOrder.getRecordType().equals("DELETE"))
					deleteOrder(instrumentBook.get(instrument), newOrder);
				else if (newOrder.getRecordType().equals("AMEND"))
					amendOrder(instrumentBook.get(instrument), newOrder);
				else if (newOrder.getRecordType().equals("OFFTR"))
					postOffTrade(instrumentBook.get(instrument), newOrder);
				else if (newOrder.getRecordType().equals("TRADE"))
					postTrade(instrumentBook.get(instrument), newOrder);
				else if (newOrder.getRecordType().equals("CANCEL_TRADE"))
					cancelTrade(instrumentBook.get(instrument), newOrder);
				else {
					System.out.println("Unrecognised order type (" + newOrder.getRecordType() + ") received.");
					System.exit(0);
				}
			}
		}
		catch (Exception e)
		{
			System.out.println("Error loading CSV file: " + e.getMessage());
		}
	}
	
	/* This function checks if the CSV file has a null/empty value (and 
	 * returns an appropriate value in that case) to avoid exceptions from
	 * the Double.valueOf() method.
	 */
	private static double makeDoubleFromCSV(String s){		
		double d = 0.0;
		if (s == null || s == "")
		{
			// We want the opposite case. Do nothing.
		}
		else
			d = Double.valueOf(s);
		
		return d;
	}
	
	/* This function checks if the CSV file has a null/empty value (and 
	 * returns an appropriate value in that case) to avoid exceptions from
	 * the Integer.valueOf() method.
	 */
	private static Integer makeIntFromCSV (String s){		
		Integer i = 0;
		
		if (s == null || s == "")
		{
			// We want the opposite case. Do nothing.
		}
		else
			i = Integer.valueOf(s);
		
		return i;
	}
	
	private static void postBid (OrderBook book, Order order){
		if (book.getBidOrderIDMap().containsKey(order.getBidID()))
			System.out.println("DUPLICATE ID " + order.getBidID());
		
		order.setOrderPriority(book.getBidPriority());
		book.getBidOrderIDMap().put(order.getBidID(), order);
		if (!book.getOrderedBids().containsKey(order.getPrice()))
			book.getOrderedBids().put(order.getPrice(), new TreeMap<Integer, String>());
		book.getOrderedBids().get(order.getPrice()).put(order.getOrderPriority(), order.getBidID());
		book.setBidPriority(book.getBidPriority() + 1);
	}
	
	private static void postAsk (OrderBook book, Order order){
		if (book.getAskOrderIDMap().containsKey(order.getAskID()))
			System.out.println("DUPLICATE ID " + order.getAskID());
		
		order.setOrderPriority(book.getAskPriority());
		book.getAskOrderIDMap().put(order.getAskID(), order);
		if (!book.getOrderedAsks().containsKey(order.getPrice()))
			book.getOrderedAsks().put(order.getPrice(), new TreeMap<Integer, String>());
		book.getOrderedAsks().get(order.getPrice()).put(order.getOrderPriority(), order.getAskID());
		book.setAskPriority(book.getAskPriority() + 1);
	}


	private static void deleteOrder (OrderBook book, Order order){
		// A delete order will only have one of askid and bidid populated so 
		// if we concatenate them we get the right ID
		String IDtoDelete = order.getAskID() + order.getBidID();
		book.getDeleteOrderIDMap().put(IDtoDelete, order);
		
		if (order.getBidAsk().equals("B"))
			book.getBidOrderIDMap().remove(IDtoDelete);
		else
			book.getAskOrderIDMap().remove(IDtoDelete);
	}
	
	private static void amendOrder (OrderBook book, Order order){
		// Check that brokerid matches on both old and new (ie user entering AMEND is allowed to change orig)
		
		// A delete order will only have one of askid and bidid populated so 
		// if we concatenate them we get the right ID
		String IDtoAmend = order.getAskID() + order.getBidID();
		book.getAmendIDMap().put(IDtoAmend, order);
		
		if (order.getBidAsk().equals("B")) {
			Order old = book.getBidOrderIDMap().get(IDtoAmend);
			old.setOldPrice(old.getPrice());
			old.setOldVolume(old.getVolume());
			old.setPrice(order.getPrice());
			old.setVolume(order.getVolume());
			
			// Overwrite the object previously stored in the map with the new values
			book.getBidOrderIDMap().put(IDtoAmend, old);
		}			
		else {
			Order old = book.getAskOrderIDMap().get(IDtoAmend);
			old.setOldPrice(old.getPrice());
			old.setOldVolume(old.getVolume());
			old.setPrice(order.getPrice());
			old.setVolume(order.getVolume());
			
			// Overwrite the object previously stored in the map with the new values
			book.getAskOrderIDMap().put(IDtoAmend, old);
		}
		
	}

	private static void postOffTrade (OrderBook book, Order order){
	
	}
	
	private static void postTrade (OrderBook book, Order order){
	
	}
	
	private static void cancelTrade (OrderBook book, Order order){
	
	}
	
}
